#include <jni.h>
#include <string>
#include <fcntl.h>
#include <errno.h>
#include <fcntl.h>
#include <libgen.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <android/log.h>

#define TAG "IOTEST"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)

extern "C" JNIEXPORT jstring JNICALL
Java_com_example_io_MainActivity_stringFromJNI(
        JNIEnv *env,
        jobject /* this */) {
    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}
const int DEFAULT_MMAP_SIZE = getpagesize();


bool zeroFillFile(int fd, size_t startPos, size_t size) {
    if (fd < 0) {
        return false;
    }

    if (lseek(fd, startPos, SEEK_SET) < 0) {
        LOGD("fail to lseek fd[%d], error:%s", fd, strerror(errno));
        return false;
    }

    static const char zeros[4096] = {0};
    while (size >= sizeof(zeros)) {
        if (write(fd, zeros, sizeof(zeros)) < 0) {
            LOGD("fail to write fd[%d], error:%s", fd, strerror(errno));
            return false;
        }
        size -= sizeof(zeros);
    }
    if (size > 0) {
        if (write(fd, zeros, size) < 0) {
            LOGD("fail to write fd[%d], error:%s", fd, strerror(errno));
            return false;
        }
    }
    return true;
}

extern "C"
JNIEXPORT void JNICALL
Java_com_example_io_MainActivity_mmapFile(JNIEnv *env, jobject instance, jstring filePath_) {

    int m_position = 0;
    const char *filePath = env->GetStringUTFChars(filePath_, 0);
    int fd = open(filePath, O_RDWR | O_CREAT, S_IRWXU);
    struct stat st;
    int r = fstat(fd, &st);
    if (r == -1) {
    }
    int fileLen = 40 * 1024 * 1024;
    zeroFillFile(fd, 0, fileLen);
    LOGD("======mmap begin=====");

    char *m_ptr = (char *) mmap(nullptr, fileLen, PROT_READ | PROT_WRITE, MAP_SHARED, fd,
                                0);
    LOGD("======mmap end=======");

    if (m_ptr == MAP_FAILED) {
        LOGD("mmap failed");
    }

    int bufferSize = 8192;
    char data[bufferSize];
    memset(data, 'a', bufferSize);
    LOGD("mmap write file begin");

    int size = fileLen / bufferSize;
    for (int i = 0; i < size; ++i) {
        memcpy(m_ptr + m_position, data, bufferSize);
        m_position += bufferSize;
    }

    LOGD("mmap write file end");

    munmap(m_ptr, fileLen);
    env->ReleaseStringUTFChars(filePath_, filePath);
    close(fd);
}
